﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Roslyn.Compilers.Common;
using Roslyn.Compilers.CSharp;
using Roslyn.Services;

namespace FernUniHagen.CompilerExtension.DataStructures
{
    /// <summary>
    /// Implement IEquatable as there might be double entries (e.g. an expression uses two 'Any' elements)
    /// </summary>
    public class SyntaxNodeInfo : IEquatable<SyntaxNodeInfo>
    {
        #region members
        private IDocument _document;
        private IdentifierNameSyntax _identifier;
        private CommonSyntaxNode _nodeToReplace;
        private SyntaxNode _referencedNode;
        //private CommonSyntaxNode _declerationNode;
        private StatementSyntax _statement;
        //   private AttributeType _attributeType;
        #endregion

        #region constructor

        public SyntaxNodeInfo(IDocument document, CommonSyntaxNode nodeToReplace)
        {
            Document = document;
            NodeToReplace = nodeToReplace;
            ReferencedNode = null;
            //  TranslationRule = translationRule;

        }

        public SyntaxNodeInfo(IDocument document, CommonSyntaxNode nodeToReplace, IdentifierNameSyntax identifier) : this(document, nodeToReplace)
        {
            Identifier = identifier;

          //  TranslationRule = translationRule;
           
        }

        public SyntaxNodeInfo(IDocument document, SyntaxNode nodeToReplace, SyntaxNode referencedNode, 
            StatementSyntax statement, IdentifierNameSyntax identifier)
            : this(document, nodeToReplace, identifier)
        {
            ReferencedNode = referencedNode;
            Statement = statement;
            
        }
        #endregion

        #region fields
        /// <summary>
        /// The SyntaxNode itself
        /// </summary>
        public CommonSyntaxNode NodeToReplace
        {
            get { return _nodeToReplace; }
            set { _nodeToReplace = value; }
        }

        /// <summary>
        /// The Document the syntaxNode is in
        /// </summary>
        public IDocument Document
        {
            get { return _document; }
            set { _document = value; }
        }

        /// <summary>
        /// The Document the syntaxNode is in
        /// </summary>
        public IdentifierNameSyntax Identifier
        {
            get { return _identifier; }
            set { _identifier = value; }
        }

        /// <summary>
        /// The new node that should be replaced
        /// </summary>
        public SyntaxNode ReferencedNode
        {
            get { return _referencedNode; }
            set { _referencedNode = value; }
        }

        public StatementSyntax Statement
        {
            get { return _statement; }
            set { _statement = value; }
        }

        #endregion

        /// <summary>
        /// From http://msdn.microsoft.com/de-de/library/vstudio/bb348436.aspx
        /// </summary>
        /// <param name="other"></param>
        /// <returns></returns>
        public bool Equals(SyntaxNodeInfo other)
        {
            if (Object.ReferenceEquals(other, null)) return false;

            //Check whether the compared object references the same data.
            if (Object.ReferenceEquals(this, other)) return true;
            //DeclerationNode.IsEquivalentTo(other.DeclerationNode) &&
            //Check whether the products' properties are equal.
            return Document.IsEquivalentTo(other.Document) && NodeToReplace.IsEquivalentTo(other.NodeToReplace) && ReferencedNode.IsEquivalentTo(other.ReferencedNode) &&
                 Statement.IsEquivalentTo(other.Statement);
               
           

        }

        public override int GetHashCode()
        {

            int hashDocument = Document == null ? 0 : Document.GetHashCode();
            int hashNodeToReplace = NodeToReplace == null ? 0 : NodeToReplace.GetHashCode();
            int hashReferencedNode = ReferencedNode == null ? 0 : ReferencedNode.GetHashCode();
           // int hashDeclerationNode = DeclerationNode == null ? 0 : DeclerationNode.GetHashCode();
            int hashStatement = Statement == null ? 0 : Statement.GetHashCode();
        
            //^ hashDeclerationNode
            //Calculate the hash code for the product.
            return hashDocument ^ hashNodeToReplace ^ hashReferencedNode  ^ hashStatement;
        }

    }

    public enum AttributeType
    {
        Any,
        Option,
        Bare,
        None
    };


}
